# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = 'restructuredtext en'
__all__ = []

from .. import formlib as layout
from .. import hint
from .. import pilelib as stack
from ..gamelib import info as gi, state, game
from ..packlib import info as cs
from ..piles import larasgame as lstack

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper


class LarasGame(game.Game):
    """
    Finish cards on _foundation_ within a turn.

    Layout
      - row [13 over 4 row, no offset]
      - talon [1 E, no offset]
      - waste [1 S, no offset]
      - reserve [18 over 4 row S, no offset]
      - foundation [4 horz, 4 vert NW, no offset]

    :CVariables:
      _row_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack
        Init all cards per. Build none. Play top.

        Cards deal back on _talon_
          - 1 card when rank is position.
          - 1 card when rank is face card.
          - 2 card when rank is ACE.
          - 2 card after _row_ turn.

      _talon_ : pysollib.stack.Stack
        .. pysollib.stacks.laragame.LarasGame_Talon (self_cards=2)
        Deal reserve back to its old row rank pile, then deal 1
        card and its new row rank pile on reserve.

      _waste_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack (max_cards=2)
        Build none. Play top on foundation.

      _foundations_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (dir=-1, base_rank=KING),
          pysollib.stack.SS_Foundation
        Build in rank by same suit. N up; E down. Play top.

      _freecell_ : None

      _hint_ : hint.AbstractHint
        .. hint.defaultHint

    note::
      ⟪highlight_play⟫ disabled. Simplified undo/redo.
    """
    __info__ = dict(id=37, name='Laraʻs Game', game_type=GT.TWO_DECK,
                    decks=2, redeals=0, skill_level=SL.BALANCED,
                    altnames=('Thirteen Packs',), version='2.99')
    __author__ = 'Markus Oberhumer'
    __version__ = 7.70

    _talon_ = Wrap(lstack.LarasGame_Talon, self_cards=2)
    _waste_ = stack.OpenStack
    _foundation_ = (Wrap(stack.SS_Foundation, dir=-1, base_rank=cs.KING),
                    stack.SS_Foundation)
    _row_ = stack.OpenStack
    _reserve_ = Wrap(stack.OpenStack, max_cards=2)
    _freecell_ = None
    _hint_ = hint.CautiousDefaultHint

    def _suits(self, index):
        return self['suits']

    def _create_game(self, rows=13, rcols=4, reserves=18, **kw):
        l, s = layout.Layout(self), self.s
        rows = l._get_row_size(self, rows, rcols)
        reserves = l._get_row_size(self, reserves, 3)
        self.table_size = (l.XM + (max(rows) + 3) * l.XS,
                     l.YM + (len(rows) + len(reserves) + 1) * l.YS)
        x = l.XM
        for j, _foundation_ in zip(range(2), self._foundations_):
            y = l.YM
            for i in self._suits(j):
                s['foundations'].append(_foundation_(x, y, game=self, suit=i))
                y += l.YS * (not j)
                x += l.XS * j
            x += l.XS * 2
        x = l.XM + l.XS,
        y += l.YS
        for row in rows:
            x = l.XM
            for i in range(row):
                s['rows'].append(self._rowstack_(x, y, game=self, offset=(0, 3)))
                x += l.XS
            y += l.YS
        x = l.XM + l.XS
        for reserve in reserves:
            x = l.XM
            for i in range(reserve):
                s['reserves'].append(self._reserve_(x, y, game=self))
            y += l.YS
        x, y = self.width - l.XS, l.YM + len(rows) * l.YS
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 's')
        l.set_rounds_text(s['talon'], 'nn', always=False)
        y -= l.YS
        s['wastes'].append(self._waste_(x, y, game=self))
        self.sg['openstacks'] = s['foundations'] + s['rows']
        self.sg['Talons'] = [s['talon']] + s['wastes']
        self.sg['dropstacks'] = s['rows'] + s['reserves']
        if self._freecell_:
            y = l.YM + l.YS / 2
            s['reserves'].append(self._freecell_(x, y, game=self))
            self.sg['openstacks'] += s['reserves'][18:]
            self.sg['dropstacks'] = s['reserves'][18:]
            self._set_region(s['reserves'][18:], l.region(x=x - l.XM))
        return l

    def _start(self):
        s = self.s
        frames, ncards = 0, len(s['talon'].cards)
        for i in range(min(ncards, 8)):
            if i == 4 or len(s['talon'].cards) <= ncards / 2:
                self._play_sound('deal')
                frames = 4
            self.dealRow(frames=frames)
        waste = s['wastes'][-1]
        waste.move_pile(len(waste.cards), s['talon'], frames=0)
        self.status = None

    @property
    def _highlight_piles(self):
        """
        Get stacks to highlight for possible move.

        :return: empty.
        :rtype: tuple
        """
        return ()

    def _log_move(self, move):
        """
        Overide: Drop history beyond move.index; no _add_stack_snapshot();
        no _timer_update(); no updateStuck()
        """
        # resize history to index then add current and status to history
        move['history'][move['index']:] += move['current']
        move['index'] += 1
        assert move['index'] == len(move['history'])

    @state.move_state('undo')
    def _undo_move(self, move):
        """
        Undo given move sequence. Override not to append snapshot.

        .. \_undo_move(move:seq(AtomicMove ...)) -> None
        """
        for atomic_move in move:
            atomic_move.undo(self)

    @state.move_state('redo')
    def _redo_move(self, move):
        """
        Redo given move sequence. Override not to append snapshot.

        .. \_redo_move(move:seq(AtomicMove ...)) -> None
        """
        for atomic_move in move:
            atomic_move.redo(self)


class RelaxedLarasGame(LarasGame):
    """
    Finish cards on _foundation_ within 2 turn.

    Layout
      - row [13 over 4 row, no offset]
      - talon [1 E, no offset]
      - waste [1 S, no offset]
      - reserve [18 over 4 row S, no offset]
      - foundation [4 horz, 4 vert NW, no offset]
      - freecell [1 NE, no offset]

    :CVariables:
      _row_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack
        Init all cards per. Build none. Play top.

        Cards deal back on _talon_
          - 1 card when rank is position.
          - 1 card when rank is face card.
          - 2 card when rank is ACE.
          - 3 card after _row_ turn.

      _talon_ : pysollib.stack.Stack
        .. pysollib.stacks.laragame.LarasGame_Talon (max_rounds=2,
          self_cards=3)
        Deal reserve back to its old row rank pile, then deal 1
        card and its new row rank pile on reserve. 2 redeals

      _waste_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack (max_cards=2)
        Build none. Play top on foundation.

      _foundations_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (dir=-1, base_rank=KING),
          pysollib.stack.SS_Foundation
        Build in rank by same suit. N up; E down. Play top.

      _freecell_ : None
        .. pysollib.stacks.laragame.LarasGame_Reserve
        Build any from another row. Play top. Max 1 card.

      _hint_ : hint.AbstractHint
        .. hint.defaultHint

    note::
      ⟪highlight_play⟫ disabled. Simplified undo/redo.

    :cvar Stack _freecell_: LarasGame_Reserve
    """
    __info__ = dict(id=13006, name='Laraʼs Game Relaxed',
                    game_type=GT.TWO_DECK, decks=2, redeals=1,
                    skill_level=SL.BALANCED,
                    version='0.50fc')
    __author__ = 'Mt. Hood Playing Card'
    __version__ = 7.70

    _talon_ = Wrap(lstack.LarasGame_Talon, max_rounds=2, self_cards=3)
    _freecell_ = lstack.LarasGame_Reserve


class DoubleLarasGame(RelaxedLarasGame):
    """
    Finish cards on _foundation_ within 2 turn.

    Layout
      - row [13 over 4 row, no offset]
      - talon [1 E, no offset]
      - waste [1 S, no offset]
      - reserve [18 over 4 row S, no offset]
      - foundation [4 horz, 4 vert NW, no offset]
      - freecell [1 NE, no offset]

    :CVariables:
      _row_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack
        Init all cards per. Build none. Play top.

        Cards deal back on _talon_
          - 1 card when rank is position.
          - 1 card when rank is face card.
          - 2 card when rank is ACE.
          - 3 card after _row_ turn.

      _talon_ : pysollib.stack.Stack
        .. pysollib.stacks.laragame.LarasGame_Talon (max_rounds=2,
          self_cards=3)
        Deal reserve back to its old row rank pile, then deal 1
        card and its new row rank pile on reserve. 2 redeals

      _waste_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack

      _reserve_ : pysollib.stack.Stack
        .. pysollib.stack.OpenStack (max_cards=2)
        Build none. Play top on foundation.

      _foundations_ : pysollib.stack.Stack
        .. pysollib.stack.SS_Foundation (dir=-1, base_rank=cs.KING, mod=13,
          max_cards=26), pysollib.stack.SS_Foundation (mod=13, max_cards=26)
        Build in rank by same suit wrap. N up; E down. Play top. Max 26 card.

      _freecell_ : None
        .. pysollib.stacks.laragame.LarasGame_Reserve (max_cards=2)
        Build any from another row. Play top. Max 2 card.

      _hint_ : hint.AbstractHint
        .. hint.defaultHint

    note::
      ⟪highlight_play⟫ disabled. Simplified undo/redo.
    """
    __info__ = dict(id=13007, name='Laraʼs Game Doubled',
                    game_type=GT.TWO_DECK, decks=4, redeals=2,
                    skill_level=SL.BALANCED, version='0.50fc')
    __author__ = 'Mt. Hood Playing Card'
    __version__ = 7.70

    _talon_ = Wrap(lstack.LarasGame_Talon, max_rounds=3, self_cards=3)
    _foundation_ = (Wrap(stack.SS_Foundation, dir=-1,
                                 base_rank=cs.KING, mod=13, max_cards=26),
                    Wrap(stack.SS_Foundation, mod=13,
                                 max_cards=26),)
    _freecell_ = Wrap(lstack.LarasGame_Reserve, max_cards=2)

PROVIDES = [LarasGame, RelaxedLarasGame, DoubleLarasGame]